{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CSV/Excel 데이터 분석 Agent\n",
    "\n",
    "Pandas DataFrame 을 활용하여 분석을 수행하는 Agent 를 생성할 수 있습니다.\n",
    "\n",
    "CSV/Excel 데이터로부터 Pandas DataFrame 객체를 생성할 수 있으며, 이를 활용하여 Agent 가 Pandas query 를 생성하여 분석을 수행할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# API 키를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API 키 정보 로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install -qU langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH15-Agent-CSV-Excel\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "df = pd.read_csv(\"./data/titanic.csv\")  # CSV 파일을 읽습니다.\n",
    "# df2 = pd.read_excel(\"./data/titanic.xlsx\", sheet_name=\"Sheet1\") # 엑셀 파일도 읽을 수 있습니다.\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_experimental.tools import PythonAstREPLTool\n",
    "\n",
    "# 파이썬 코드를 실행하는 도구를 생성합니다.\n",
    "python_tool = PythonAstREPLTool()\n",
    "python_tool.locals[\"df\"] = df\n",
    "\n",
    "\n",
    "# 도구 호출 시 실행되는 콜백 함수입니다.\n",
    "def tool_callback(tool) -> None:\n",
    "    print(f\"<<<<<<< Code >>>>>>\")\n",
    "    if tool_name := tool.get(\"tool\"):  # 도구에 입력된 값이 있다면\n",
    "        if tool_name == \"python_repl_ast\":\n",
    "            tool_input = tool.get(\"tool_input\")\n",
    "            for k, v in tool_input.items():\n",
    "                if k == \"query\":\n",
    "                    print(v)  # Query 를 출력합니다.\n",
    "                    result = python_tool.invoke({\"query\": v})\n",
    "                    print(result)\n",
    "    print(f\"<<<<<<< Code >>>>>>\")\n",
    "\n",
    "\n",
    "# 관찰 결과를 출력하는 콜백 함수입니다.\n",
    "def observation_callback(observation) -> None:\n",
    "    print(f\"<<<<<<< Message >>>>>>\")\n",
    "    if \"observation\" in observation:\n",
    "        print(observation[\"observation\"])\n",
    "    print(f\"<<<<<<< Message >>>>>>\")\n",
    "\n",
    "\n",
    "# 최종 결과를 출력하는 콜백 함수입니다.\n",
    "def result_callback(result: str) -> None:\n",
    "    print(f\"<<<<<<< 최종 답변 >>>>>>\")\n",
    "    print(result)\n",
    "    print(f\"<<<<<<< 최종 답변 >>>>>>\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent\n",
    "from langchain.agents.agent_types import AgentType\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_teddynote.messages import AgentStreamParser, AgentCallbacks\n",
    "\n",
    "agent = create_pandas_dataframe_agent(\n",
    "    ChatOpenAI(model=\"gpt-4o\", temperature=0),\n",
    "    df,\n",
    "    verbose=False,\n",
    "    agent_type=\"tool-calling\",\n",
    "    allow_dangerous_code=True,\n",
    "    prefix=\"You are a professional data analyst and expert in Pandas. \"\n",
    "    \"You must use Pandas DataFrame(`df`) to answer user's request. \"\n",
    "    \"\\n\\n[IMPORTANT] DO NOT create or overwrite the `df` variable in your code. \\n\\n\"\n",
    "    \"If you are willing to generate visualization code, please use `plt.show()` at the end of your code. \"\n",
    "    \"I prefer seaborn code for visualization, but you can use matplotlib as well.\"\n",
    "    \"\\n\\n<Visualization Preference>\\n\"\n",
    "    \"- `muted` cmap, white background, and no grid for your visualization.\"\n",
    "    \"\\nRecomment to set palette parameter for seaborn plot.\",\n",
    ")\n",
    "\n",
    "parser_callback = AgentCallbacks(tool_callback, observation_callback, result_callback)\n",
    "stream_parser = AgentStreamParser(parser_callback)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ask(query):\n",
    "    # 질의에 대한 답변을 출력합니다.\n",
    "    response = agent.stream({\"input\": query})\n",
    "\n",
    "    for step in response:\n",
    "        stream_parser.process_agent_steps(step)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 질의에 대한 답변을 출력합니다.\n",
    "response = agent.stream({\"input\": \"corr() 을 구해서 히트맵 시각화\"})\n",
    "\n",
    "for step in response:\n",
    "    stream_parser.process_agent_steps(step)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ask(\"몇 개의 행이 있어?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ask(\"남자와 여자의 생존율의 차이는 몇이야?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ask(\"남자 승객과 여자 승객의 생존율을 구한뒤 barplot 차트로 시각화 해줘\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ask(\"1,2 등급에 탑승한 10세 이하 어린 아이의 성별별 생존율을 구하고 시각화 하세요\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-lwwSZlnu-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
